`include "defines.v"

module mem_stage (

    // 从执行阶段获得的信息
    input  wire [`ALUOP_BUS     ]       mem_aluop_i,
    input  wire [`REG_ADDR_BUS  ]       mem_wa_i,
    input  wire                         mem_wreg_i,
    input  wire [`REG_BUS       ]       mem_wd_i,
    input  wire                         mem_mreg_i,
    input  wire [`REG_BUS      ]        mem_din_i,
    input  wire [`INST_ADDR_BUS]        mem_debug_wb_pc,  // 供调试使用的PC值，上板测试时务必删除该信号
    
    // 送至写回阶段的信息
    output wire [`ALUOP_BUS     ]       mem_aluop_o,
    output wire [`REG_ADDR_BUS  ]       mem_wa_o,
    output wire                         mem_wreg_o,
    output wire [`REG_BUS       ]       mem_dreg_o,
    output wire                         mem_mreg_o,
    //output wire [`REG_BUS      ]        mem_din_o,
    output wire [`BSEL_BUS     ]        mem_dre_o,
    
    // 送入数据存储器
    output wire                         dce,
    output wire [`INST_ADDR_BUS     ]   daddr,
    output wire [`BSEL_BUS          ]   we, 
    output wire [`REG_BUS           ]   din,
    
    output wire [`INST_ADDR_BUS] 	    debug_wb_pc  // 供调试使用的PC值，上板测试时务必删除该信号
    );

    // 如果当前不是访存指令，则只需要把从执行阶段获得的信息直接输出
    assign mem_aluop_o  = mem_aluop_i;
    assign mem_wa_o     = mem_wa_i;
    assign mem_wreg_o   = mem_wreg_i;
    assign mem_dreg_o   = mem_wd_i;
    assign mem_mreg_o   = mem_mreg_i;
    
    assign debug_wb_pc = mem_debug_wb_pc;    // 上板测试时务必删除该语句 
    
    wire inst_ld_b = (mem_aluop_i == `LA_LD_B);//?:
    wire inst_st_b = (mem_aluop_i == `LA_ST_B);
    wire inst_ld_w = (mem_aluop_i == `LA_LD_W);
    wire inst_st_w = (mem_aluop_i == `LA_ST_W);

    assign dce = (inst_ld_b | inst_st_b | inst_ld_w | inst_st_w);
    assign mem_dre_o[3] = (inst_ld_b & (daddr[1:0] == 2'b00)) | inst_ld_w;
    assign mem_dre_o[2] = (inst_ld_b & (daddr[1:0] == 2'b01)) | inst_ld_w;
    assign mem_dre_o[1] = (inst_ld_b & (daddr[1:0] == 2'b10)) | inst_ld_w;
    assign mem_dre_o[0] = (inst_ld_b & (daddr[1:0] == 2'b11)) | inst_ld_w;
    assign we[3] = (inst_st_b & (daddr[1:0] == 2'b00)) | inst_st_w;
    assign we[2] = (inst_st_b & (daddr[1:0] == 2'b01)) | inst_st_w;
    assign we[1] = (inst_st_b & (daddr[1:0] == 2'b10)) | inst_st_w;
    assign we[0] = (inst_st_b & (daddr[1:0] == 2'b11)) | inst_st_w;
    // 小端序写入
    assign din = (we == 4'b1111) ? {mem_din_i[7:0],mem_din_i[15:8],mem_din_i[23:16],mem_din_i[31:24]} : {mem_din_i[7:0],mem_din_i[7:0],mem_din_i[7:0],mem_din_i[7:0]};
    assign daddr = mem_wd_i;

endmodule